home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / satellit / radserv / radsrv.c < prev    next >
C/C++ Source or Header  |  1995-01-23  |  17KB  |  625 lines

  1. /* %W% %E% %U% */
  2.  
  3. /*
  4.  * VersaTrack Radio Control Server Template.
  5.  *
  6.  * This code DOES NOT CONTROL ANY EXTERNAL DEVICE.
  7.  *
  8.  * This is a just skeleton program that shows how to communicate with
  9.  * VersaTrack. The code for reading/writing an NT-supported COM port
  10.  * is and also provided. It can be used as a starting point to develop
  11.  * a radio or rotator control server (or similar program.)
  12.  *
  13.  * ALL DISCLAIMERS APPLY! THIS PROGRAM IS PROVIDED FREE AND AS IS.
  14.  * YOU USE IT ENTIERLY AT YOU OWN RISK. IN NO EVENT THE AUTHOR SHALL BE
  15.  * LIABLE FOR ANY DIRECT, IMPLIED OR CONSEQUENTIAL DAMAGE ARISING OUT OF
  16.  * OR RELATED TO ITS USE. THERE IS NO WARANTY OR SUPPORT AND THE AUTHOR
  17.  * DOES NOT MAKE ANY REPRESENTATION, INCLUDING BUT NOT LIMITED TO THOSE
  18.  * OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #include "resource.h"
  22. #include "radextrn.h"
  23.  
  24. char textbuf[BUFLEN];
  25. char tmpbuf[BUFLEN]; 
  26. char msgbuf[BUFLEN]; 
  27. char VersionStr[48];
  28.  
  29. HANDLE      hInst;                   /* Instance handle                     */
  30. HANDLE      ServerThread;            /* server thread handle                */
  31. HWND        Gwnd;                    /* global copy of our window handle    */
  32. HWND        vsthwnd;                 /* global copy of versatrk window hanlde*/
  33. HWND        rdhwnd;                  /* handle of radio display dialog box  */
  34. DWORD       vstth;                   /* handle of versatrk's main thread     */
  35. DWORD       vstpid;                  /* gloabl copy of versatrk process ID  */
  36. HCURSOR     hcurSave;                /* Last cursor                         */
  37. HCURSOR     hWait;                   /* handle of hourglass cursor icon     */
  38. HICON       hAsterisk, hQuestion;    /* dialog box decorations              */
  39. int         srv_state;               /* Server State                        */
  40. BOOL        NoClientOk;              /* If non-zero, go on w/out client present */
  41. HANDLE      pipeh;                   /* pipe handle to Versatrack client    */
  42. CRITICAL_SECTION    VstLock;         /* Lock to update VST window ID        */
  43.  
  44. void nullfunc(va_list vlist, ...) { }
  45. void (*diag)(va_list vlist, ...);
  46.  
  47.  
  48. int WINAPI WinMain(hInst, hPrevInst, CmdLinePtr, CmdShow)
  49. HANDLE hInst, hPrevInst;
  50. char *CmdLinePtr;
  51. int CmdShow;
  52. {
  53.     MSG msg;
  54.     extern BOOL InitInstance(HANDLE, HANDLE, int);
  55.     extern BOOL InitApplication(HANDLE);
  56.  
  57.     diag = nullfunc; 
  58.     hInst = hInst;
  59.     NoClientOk = FALSE;
  60.  
  61.     if (!InitApplication(hInst))
  62.         return 1;
  63.  
  64.     if (!InitInstance(hInst, hPrevInst, CmdShow))
  65.         return 1;
  66.     
  67.     while (GetMessage(&msg, (UINT)NULL, (UINT)NULL, (UINT)NULL)) {
  68.         TranslateMessage(&msg);
  69.         DispatchMessage(&msg);
  70.     }
  71.     return 0;
  72. }
  73.  
  74.  
  75. BOOL InitApplication(hInst)
  76. HANDLE hInst;
  77. {
  78.     WNDCLASS wc;
  79.     extern BOOL CALLBACK MainWndProc();
  80.     BOOL r;
  81.  
  82.     wc.style = CS_OWNDC ;
  83.     wc.lpfnWndProc = (WNDPROC) MainWndProc;
  84.     wc.cbClsExtra = 0;
  85.     wc.cbWndExtra = 0;
  86.     wc.hInstance = hInst;
  87.     wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_RADICON));
  88.     wc.hCursor = hcurSave = LoadCursor(NULL, IDC_CROSS);
  89.     wc.hbrBackground = GetStockObject(GRAY_BRUSH);
  90.     wc.lpszMenuName =  MAKEINTRESOURCE(IDR_RAD_MENU);
  91.     wc.lpszClassName = "VSTRADIOSRV";
  92.  
  93.     r = RegisterClass(&wc);
  94.  
  95.     hAsterisk = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ASTERISK));
  96.     hQuestion = LoadIcon(NULL, MAKEINTRESOURCE(IDI_QUESTION));
  97.     hWait = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
  98.  
  99.     InitializeCriticalSection(&VstLock);
  100.  
  101.     sprintf(VersionStr,"Radio Cntl Skeleton Sample");
  102.  
  103.     return r;
  104. }
  105.  
  106. BOOL InitInstance(hInstance, hPrev, CmdShow)
  107. HANDLE hInstance, hPrev;
  108. int CmdShow;
  109. {
  110.     HWND hWnd;
  111.  
  112.     hInst = hInstance;
  113.     hWnd = CreateWindow("VSTRADIOSRV", "Radio Cntl Skeleton Sample",
  114.         WS_OVERLAPPEDWINDOW | WS_BORDER | WS_CLIPCHILDREN,
  115.         0, 0,  300, 100, NULL, NULL, hInst, NULL );
  116.         
  117.     if (hWnd == NULL)
  118.         return FALSE;
  119.  
  120.     Gwnd = hWnd;
  121.     UpdateWindow(hWnd);
  122.     ShowWindow(hWnd, SW_SHOWMINIMIZED);
  123.  
  124.     return TRUE;
  125. }
  126.  
  127.  
  128. BOOL CALLBACK
  129. MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  130. {
  131.     int cmd;
  132.     extern BOOL SaveParams(void);
  133.     extern BOOL TTYProc(tty_t *);
  134.     extern BOOL ReadParams(void);
  135.     extern BOOL CALLBACK RadioDisplay(HWND, UINT, WPARAM, LPARAM);
  136.           
  137.     Gwnd = hWnd;
  138.     switch (message) {        
  139.     case WM_CREATE:
  140.         if (!GetSystemMetrics(SM_MOUSEPRESENT))
  141.             fatal("Radio server requires the use of a mouse");
  142.  
  143. #ifdef _DEBUG_
  144.         diag = DebugFunc;
  145.         diag("Debug console opened.\n");
  146. #endif /* _DEBUG_ */
  147.  
  148.         ReadParams();
  149.  
  150.         if (!ServerCreate())
  151.             fatal("Unable to create service thread");
  152.  
  153.         break;
  154.  
  155.     case WM_TIMER:
  156.  
  157.         cmd = LOWORD(wParam);
  158.  
  159.         switch (cmd) {
  160.  
  161.         case IDT_HEARTBEAT:
  162.             if (NoClientOk) {
  163.                 KillTimer(hWnd, IDT_HEARTBEAT);
  164.                 break;
  165.             }
  166.             if (!VstIsAlive()) {
  167. #ifdef _DEBUG
  168.                 diag("Lost VersaTrack Heartbeat\n");
  169. #endif /* _DEBUG_ */
  170.                 KillTimer(hWnd, IDT_HEARTBEAT);
  171.                 PostMessage(hWnd, CNTRL_CLIENTEXIT, (WPARAM)0, (LPARAM)0);
  172.             }
  173.             break;
  174.             
  175.         default:
  176.             break;
  177.         }
  178.         break;
  179.         
  180.     case SERVER_CLIENTINIT: /* received as a result of a "hello" */
  181.  
  182.         VST_LOCK();
  183.         vsthwnd = (HWND) lParam;
  184.         vstth = vstpid = 0L;
  185.         vstth = GetWindowThreadProcessId(vsthwnd, &vstpid);
  186.         VST_UNLOCK();
  187.  
  188.         NoClientOk = FALSE;
  189.  
  190.         /* Check every 5 secs to see if VersaTrack is alive */
  191.  
  192.         SetTimer(hWnd, IDT_HEARTBEAT, (DWORD) 5000, (TIMERPROC) NULL);
  193.         break;
  194.  
  195.     case WM_CANCELMODE:
  196.         ReleaseCapture();
  197.         break;
  198.         
  199.     case WM_COMMAND:
  200.         cmd = LOWORD(wParam);
  201.         switch (cmd) {
  202.             case IDM_OPTIONS_COMPORT:
  203.                 PortParams();
  204.                 break;
  205.                 
  206.             case IDM_OPTIONS_SETTINGS:
  207.                 RadioParams();
  208.                 break;
  209.  
  210.             case IDM_OPTIONS_SAVESETTINGS:
  211.                 SaveParams();
  212.                 break;
  213.  
  214.             case IDM_ACTIVATE:
  215.                 if (!TTYProc(&rigInfo.tty))
  216.                     usermsg("connection to radio failed");
  217.  
  218.                 if (!rdhwnd)
  219.                     rdhwnd = CreateDialog(hInst,
  220.                         MAKEINTRESOURCE(IDD_RADIO_DISPLAY), hWnd, RadioDisplay);
  221.                 break;
  222.                 
  223.             case IDM_DEACTIVATE:
  224.                 if (rdhwnd) {
  225.                     DestroyWindow(rdhwnd);
  226.                     rdhwnd = NULL;
  227.                 }
  228.                 break;
  229.                 
  230.             default:
  231.                 break;
  232.         }
  233.         break;
  234.  
  235.     case WM_MOUSEACTIVATE:
  236.         return MA_ACTIVATE;
  237.  
  238.     case WM_CLOSE:
  239.         KillTimer(hWnd, IDT_HEARTBEAT);
  240.         goto defaction;
  241.  
  242.     case CNTRL_CLIENTEXIT:
  243.         if (!yesno("No VersaTrack Heartbeat! Do you wish to exit ?")) {
  244.             NoClientOk = TRUE;
  245.             break;
  246.         }
  247.         Sleep(0);
  248.         /* FALL THROUGH */
  249.    
  250.     case WM_DESTROY:
  251.         KillTimer(hWnd, IDT_HEARTBEAT);
  252.         PostQuitMessage(0);
  253.         break;
  254.         
  255.     default:
  256.     defaction:
  257.         return DefWindowProc(hWnd, message, wParam, lParam);
  258.     }
  259.     return 0L;
  260. }
  261.  
  262.  
  263. static BOOL CALLBACK
  264. RadUserMsg(hwnd, message, wParam, lParam)
  265. HWND hwnd;
  266. UINT message;
  267. WPARAM wParam;
  268. LPARAM lParam;
  269. {
  270.     int action;
  271.     POINT *p;
  272.     HDC hdc;
  273.         
  274.     switch(message) {
  275.     case WM_INITDIALOG:
  276.         p = DialogPos(Gwnd, hwnd);
  277.         SendDlgItemMessage(hwnd, IDC_XMSGTEXT, WM_SETTEXT, 0, (LPARAM) msgbuf);
  278.         SetWindowPos(hwnd, HWND_TOPMOST, (int)p->x, (int)p->y, 0, 0,
  279.             SWP_NOSIZE|SWP_SHOWWINDOW);
  280.         /* FALL THROUGH */
  281.         
  282.     case WM_PAINT:
  283.         hdc = GetDC(hwnd);
  284.         DrawIcon(hdc, 12, 17, hAsterisk);
  285.         ReleaseDC(hwnd, hdc);
  286.         break;
  287.  
  288.     case WM_COMMAND:
  289.         action = LOWORD(wParam);
  290.         if (action == IDOK) {
  291.             EndDialog(hwnd, wParam);
  292.             return TRUE;
  293.         }
  294.         break;
  295.     }
  296.     return FALSE;
  297. }
  298.  
  299. static BOOL CALLBACK
  300. RadYesNo(hwnd, message, wParam, lParam)
  301. HWND hwnd;
  302. UINT message;
  303. WPARAM wParam;
  304. LPARAM lParam;
  305. {
  306.     int action;
  307.     POINT *p;
  308.     HDC hdc;
  309.  
  310.     switch(message) {
  311.     case WM_INITDIALOG:
  312.         p = DialogPos(Gwnd, hwnd);
  313.         SendDlgItemMessage(hwnd, IDC_XYESNOTEXT, WM_SETTEXT, 0, (LPARAM) msgbuf);
  314.         SendMessage(hwnd, DM_SETDEFID, (WPARAM) IDOK, (LPARAM) 0);
  315.         SetWindowPos(hwnd, HWND_TOPMOST, (int)p->x, (int)p->y, 0, 0,
  316.             SWP_NOSIZE | SWP_SHOWWINDOW);
  317.         /* FALL THROUGH */
  318.     case WM_PAINT:
  319.         hdc = GetDC(hwnd);
  320.         DrawIcon(hdc, 14, 20, hQuestion);
  321.         ReleaseDC(hwnd, hdc);
  322.         break;
  323.  
  324.     case WM_COMMAND:
  325.         action = LOWORD(wParam);
  326.         if (action == IDOK || action == IDCANCEL) {
  327.             EndDialog(hwnd, (LOWORD(wParam) == IDOK) ? TRUE : FALSE);
  328.             EnableWindow(GetParent(hwnd), TRUE);
  329.             return TRUE;
  330.         }
  331.         break;
  332.     }
  333.     return FALSE;
  334. }
  335.  
  336. void
  337. usermsg(msg)
  338. char *msg;
  339. {
  340.     int flag;
  341.     strcpy(msgbuf,msg);
  342.  
  343.     if ((flag = IsIconic(Gwnd))) {
  344.         OpenIcon(Gwnd);
  345.         EnableWindow(Gwnd, TRUE);
  346.     }
  347.     DialogBox(hInst, MAKEINTRESOURCE(IDD_XMESSAGE), Gwnd, RadUserMsg);
  348.     if (flag)
  349.         CloseWindow(Gwnd);
  350.     else
  351.         EnableWindow(Gwnd, TRUE);
  352. }
  353.  
  354.  
  355. int
  356. yesno(msg)
  357. char *msg;
  358. {
  359.     int r, flag;    
  360.     strcpy(msgbuf,msg);
  361.  
  362.     if (flag = IsIconic(Gwnd)) {
  363.         OpenIcon(Gwnd);
  364.         EnableWindow(Gwnd, TRUE);
  365.     }
  366.     r = DialogBox(hInst, MAKEINTRESOURCE(IDD_XYESNO), Gwnd, RadYesNo);
  367.     if (flag)
  368.         CloseWindow(Gwnd);
  369.     else
  370.         EnableWindow(Gwnd, TRUE);
  371.     return r;
  372. }
  373.  
  374. void
  375. fatal(s)
  376. char *s;
  377. {
  378.     char xbuf[256];
  379.     sprintf(xbuf,"ERROR: %s (code %d)",s,GetLastError());
  380.     usermsg(s);
  381.     ExitProcess(1);
  382. }
  383.  
  384.  
  385. POINT *
  386. DialogPos(pwnd, cwnd)
  387. HWND pwnd, cwnd;    /* position cwnd in center of pwnd */
  388. {
  389.     RECT pr,cr;
  390.     static POINT p;
  391.     int xmax,ymax;
  392.  
  393.     if (pwnd == NULL)
  394.         pwnd = GetParent(cwnd);
  395.  
  396.     xmax = GetSystemMetrics(SM_CXSCREEN);
  397.     ymax = GetSystemMetrics(SM_CYSCREEN);
  398.  
  399.     GetClientRect(pwnd,&pr);
  400.     GetClientRect(cwnd,&cr);
  401.  
  402.     p.x = p.y = 0;
  403.     ClientToScreen(pwnd,&p);    /* upper left corner of parent on screen */
  404.     if ((p.x < 20) || (p.x + (pr.right - pr.left)) > xmax+20) {
  405.         pr.left = 0;
  406.         pr.right = xmax;
  407.         p.x = 0;
  408.     }
  409.     if ((p.y < 20) || (p.y + (pr.bottom - pr.top)) > ymax+20) {
  410.         pr.top = 0;
  411.         pr.bottom = ymax;
  412.         p.y = 0;
  413.     }
  414.     p.x += ((pr.right - pr.left) - (cr.right - cr.left)) / 2;
  415.     p.y += ((pr.bottom - pr.top) - (cr.bottom - cr.top)) / 2;
  416.     
  417.     return &p;
  418. }
  419.  
  420.  
  421. void
  422. NormCursor()
  423. {
  424.     SetWindowText(Gwnd, VersionStr);
  425.     SetCursor(hcurSave);
  426.     SetClassLong(Gwnd, GCL_HCURSOR, (LONG) hcurSave);
  427. }
  428.  
  429. void
  430. WaitCursor()
  431. {
  432.     SetCursor(hWait);
  433.     SetClassLong(Gwnd, GCL_HCURSOR, (LONG) hWait);
  434.     SetWindowText(Gwnd,"Waiting");
  435. }
  436.  
  437.  
  438. static BOOL
  439. VstIsAlive()
  440. {
  441.     int status;
  442.     
  443.     VST_LOCK();      
  444.     if (vsthwnd == NULL) {
  445.         VST_UNLOCK();
  446.         return FALSE;
  447.     }
  448.     /* If the post succeeds, VersaTrack thread is still there. It will
  449.      * simply read and discard the message. If it's not there, we'll get
  450.      * an error and PostThreadMessage() will return FALSE.
  451.      */
  452.     status = PostThreadMessage(vstth, VST_PROBE_AYT, (WPARAM) 0, (LPARAM) Gwnd);
  453.     VST_UNLOCK();
  454.     return status;
  455. }
  456.  
  457.  
  458. static BOOL
  459. ServerCreate()
  460. {
  461.     long dummy;
  462.     extern void RadServerProc();
  463.  
  464.     WaitCursor();    
  465.     ServerThread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL,  (DWORD)0,
  466.         (LPTHREAD_START_ROUTINE)RadServerProc, (LPVOID)&Gwnd,
  467.         (DWORD)0, (LPDWORD)&dummy);
  468.  
  469.     if (ServerThread == INVALID_HANDLE_VALUE)
  470.         ServerThread = NULL;
  471.  
  472.     return ServerThread != INVALID_HANDLE_VALUE;
  473. }
  474.  
  475.  
  476. static void
  477. RadServerProc(HWND *hWnd)
  478. {
  479.     HANDLE      hPipe, rdEvent;
  480.     BOOL        done = FALSE;
  481.     HWND        wid;
  482.     OVERLAPPED  ovrlap;
  483.     PSECURITY_DESCRIPTOR  sdp;
  484.     SECURITY_ATTRIBUTES   sa, *sap;
  485.     int         ret, error, nread, seq, update, lastseq;
  486.     static int  vver, pver;
  487.     double      melev, loss, az, el, range, rrate;
  488.     char        inbuf[256];
  489.     char        satname[48], sitename[64];
  490.     char        reason[64], mode[6];
  491.  
  492.     extern void r_control(char *, double, double, double, double);
  493.     extern void r_interrupt(char *, char *);
  494.     extern void r_init(char *, char *, char *, int);
  495.     extern void r_special(int);
  496.     extern void r_begin(HWND);
  497.     extern void r_end(HWND);
  498.  
  499.     /* This should prevent server's access rights to the pipe to become
  500.      * inheritable. Not really needed for VersaTrack, but good
  501.      * prog. practice in general.
  502.      */
  503.     sdp = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
  504.                 SECURITY_DESCRIPTOR_MIN_LENGTH);
  505.     sap = NULL;
  506.     if (sdp) {
  507.         InitializeSecurityDescriptor(sdp, SECURITY_DESCRIPTOR_REVISION);
  508.         SetSecurityDescriptorDacl(sdp, TRUE, (PACL) NULL, FALSE);
  509.         sap = &sa;
  510.     }
  511.  
  512.     sa.nLength = sizeof(sa);
  513.     sa.lpSecurityDescriptor = sdp;
  514.     sa.bInheritHandle = FALSE;
  515.  
  516.     hPipe = CreateNamedPipe ("\\\\.\\PIPE\\_VRADIO_",
  517.         PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  518.         PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE,
  519.         PIPE_UNLIMITED_INSTANCES, 4096, 4096,  0, sap);
  520.  
  521.     if ( hPipe == INVALID_HANDLE_VALUE )
  522.         fatal("Service Thread: Can't create service pipe - Server Exiting");
  523.  
  524.     rdEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  525.     memset ((void *)&ovrlap, 0, sizeof(OVERLAPPED));
  526.     ovrlap.hEvent = rdEvent;
  527.  
  528. #ifdef _DEBUG_
  529.     diag("Pipe Created. Awaiting connection\n");
  530. #endif /* _DEBUG_ */
  531.   
  532.  again:
  533.     wid = NULL;
  534.     WaitCursor();
  535.     ConnectNamedPipe(hPipe, NULL);
  536.     NormCursor();
  537.     
  538. #ifdef _DEBUG_
  539.     diag("Pipe connected.\n");
  540. #endif /* _DEBUG_ */
  541.  
  542.     /* VersaTrack messages service loop */
  543.     
  544.     do {
  545.         inbuf[0] = 0;
  546.         ret = ReadFile (hPipe, inbuf, 100, &nread, &ovrlap);
  547.         error = GetLastError();
  548.         if (ret == FALSE) {
  549.             switch (error) {
  550.             case ERROR_IO_PENDING:
  551.                 WaitForSingleObject (rdEvent, (DWORD)-1);
  552.                 break;
  553.  
  554.             default:
  555. #ifdef _DEBUG_
  556.                 diag("Pipe I/O error (code %d) - Disconnecting...\n", GetLastError());
  557. #endif /* _DEBUG_ */
  558.                 DisconnectNamedPipe(hPipe);
  559.                 Sleep(0);
  560.                 r_end(wid);
  561.                 goto again;
  562.             }
  563.         }
  564.         if (!done) {
  565.             if (!GetOverlappedResult (hPipe, &ovrlap, &nread, FALSE)) {
  566. #ifdef _DEBUG_
  567.                 diag("Pipe I/O error (code %d) - Disconnecting...\n", GetLastError());
  568. #endif /* _DEBUG_ */
  569.                 DisconnectNamedPipe(hPipe);
  570.                 Sleep(0);
  571.                 r_end(wid);
  572.                 goto again;
  573.             }
  574.             /* Assume valid message and dispatch per message type */
  575.             inbuf[nread] = 0;
  576.             switch (inbuf[0]) {
  577.             case '+':               /* NORMAL MODE MSG */
  578.                 if (sscanf(inbuf+2,"%d AZ %lf EL %lf RNG %lf DV %lf PL %lf %s",
  579.                     &seq, &az, &el, &range, &rrate, &loss, satname))
  580.                     if (++lastseq == seq)
  581.                         r_control(satname, el, range, rrate, loss);
  582.                 break;
  583.  
  584.             case '!':               /* INTERRUPTION MSG */
  585.                 if (sscanf(inbuf+2,"%d '%[^']'", &seq, reason))
  586.                     if (++lastseq == seq)
  587.                         r_interrupt(satname, reason);
  588.                 break;
  589.  
  590.             case '*':               /* INITIALIZTION/RESET MSG */
  591.                 mode[3] = 0;
  592.                 if (sscanf(inbuf+2,"%d INIT UPD %d MIE %lf MD '%[^']' SITE '%[^']' SAT '%[^']'",
  593.                     &seq, &update, &melev, mode, sitename, satname))
  594.                     if (++lastseq == seq)
  595.                         r_init(satname, sitename, mode, update);
  596.                 break;
  597.  
  598.             case '>':               /* NEW CONNECTION FROM VERSATRACK */
  599.                 if (sscanf(inbuf+2,"HELLO %d %d WH %x SEQ %d", &vver, &pver,
  600.                     &wid, &seq)) {
  601.                     PostMessage(Gwnd, SERVER_CLIENTINIT, (WPARAM)0, (LPARAM)wid);
  602.                     lastseq = seq;
  603.                     r_begin(wid);
  604.                 }
  605.                 break;
  606.  
  607.             default:
  608.                 break;
  609.             }
  610.         }        
  611.     } while(!done);
  612.  
  613.     DisconnectNamedPipe(hPipe);
  614.     CloseHandle(hPipe);
  615.     CloseHandle(rdEvent);
  616.     DeleteObject(rdEvent);
  617.     LocalFree(sdp);
  618. #ifdef _DEBUG_
  619.     diag("server thread exiting...\n");
  620. #endif /* _DEBUG_ */
  621.     ServerThread = NULL;
  622.     ExitThread(0);
  623. }
  624.  
  625.